package com.techsoft.session;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ConcurrentHashMap;

import com.techsoft.Cache;
import com.techsoft.Session;
import com.techsoft.cache.CacheFactory;

public class SessionManager {
	private static SessionManager instance = null;
	private Map<String, Session> sessions = null;
	private ScheduledExecutorService executor = null;
	private SessionMonitor sessionMonitor;

	private SessionManager() {
		sessions = new ConcurrentHashMap<String, Session>();
		executor = new ScheduledThreadPoolExecutor(1);
		sessionMonitor = new SessionMonitor();
		executor.scheduleWithFixedDelay(sessionMonitor, 0, 30, TimeUnit.MINUTES);
	}

	private void updateSessionLastAccessTime(Session session) {
		session.setLastAccessTime(System.currentTimeMillis());
		if (!CacheFactory.setValue(LocalSession.class.getName(), session.getAuthToken(), session)) {
			sessions.put(session.getAuthToken(), session);
		}
	}

	public static SessionManager getInstance() {
		if (instance == null) {
			instance = new SessionManager();
		}

		return instance;
	}

	public Session getSession(String token) {
		Session result = (Session) CacheFactory.getValue(LocalSession.class.getName(), token);

		if (result == null) {
			result = sessions.get(token);
		}

		updateSessionLastAccessTime(result);

		return result;
	}

	public Session CreateLocalSession(String clientSessionID) {
		Session result = new LocalSession(clientSessionID);
		if (CacheFactory.getIsValid()) {
			CacheFactory.setValue(LocalSession.class.getName(), result.getAuthToken(), result);
		} else {
			sessions.put(result.getAuthToken(), result);
		}

		return result;
	}

	public void setSession(Session session) {
		if (CacheFactory.getIsValid()) {
			CacheFactory.setValue(LocalSession.class.getName(), session.getAuthToken(), session);
		} else {
			sessions.put(session.getAuthToken(), session);
		}
	}

	public boolean validSession(String token, String sessionId) {
		boolean result = false;
		Session session = this.getSession(token);
		if (session != null) {
			if (session.getClientSessionID().equals(sessionId)) {
				result = true;
			}
		}

		return result;
	}

	private class SessionMonitor implements Runnable {
		private boolean running = false;

		@Override
		public void run() {
			synchronized (this) {
				if (running) {
					return;
				}
				running = true;
			}

			try {
				String key = null;
				Iterator<String> keys = null;
				Long sessionidletime = null;
				Cache<String, Session> cache = CacheFactory.getCache(LocalSession.class.getName());
				if (cache != null) {
					keys = cache.keySet().iterator();
					while (keys.hasNext()) {
						key = keys.next();
						Session session = cache.get(key);
						sessionidletime = session.getLastAccessTime() + Session.IDLETIME * 1000;
						if (System.currentTimeMillis() <= sessionidletime) {
							cache.remove(key);
						}
					}
				}

				keys = sessions.keySet().iterator();
				while (keys.hasNext()) {
					key = keys.next();
					Session session = sessions.get(key);
					sessionidletime = session.getLastAccessTime() + Session.IDLETIME * 1000;
					if (System.currentTimeMillis() <= sessionidletime) {
						sessions.remove(key);
					}
				}
			} finally {
				synchronized (this) {
					running = false;
				}
			}
		}
	}
}
